package com.lineage.server.model.Instance;

import com.lineage.server.datatables.DeNameTable;
import com.lineage.server.datatables.DeShopItemTable;
import com.lineage.server.datatables.DeTitleTable;
import com.lineage.server.datatables.SprTable;
import com.lineage.server.datatables.lock.ClanReading;
import com.lineage.server.model.L1AttackPc;
import com.lineage.server.model.L1Character;
import com.lineage.server.model.L1Location;
import com.lineage.server.model.L1Object;
import com.lineage.server.model.map.L1Map;
import com.lineage.server.serverpackets.S_ChangeHeading;
import com.lineage.server.serverpackets.S_ChangeShape;
import com.lineage.server.serverpackets.S_CharVisualUpdate;
import com.lineage.server.serverpackets.S_Chat;
import com.lineage.server.serverpackets.S_ChatGlobal;
import com.lineage.server.serverpackets.S_ChatTransaction;
import com.lineage.server.serverpackets.S_DoActionGFX;
import com.lineage.server.serverpackets.S_DoActionShop;
import com.lineage.server.serverpackets.S_Fishing;
import com.lineage.server.serverpackets.S_NPCPack_De;
import com.lineage.server.serverpackets.S_SkillBrave;
import com.lineage.server.serverpackets.S_SkillSound;
import com.lineage.server.serverpackets.ServerBasePacket;
import com.lineage.server.templates.DeName;
import com.lineage.server.templates.L1EmblemIcon;
import com.lineage.server.templates.L1Npc;
import com.lineage.server.thread.DeAiThreadPool;
import com.lineage.server.types.Point;
import com.lineage.server.utils.ListMapUtil;
import com.lineage.server.world.World;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Random;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class L1DeInstance extends L1NpcInstance {
  private static final long serialVersionUID = 1L;
  
  private static final Log _log = LogFactory.getLog(L1DeInstance.class);
  
  private static final Random _random = new Random();
  
  private static final ArrayList<DeName> _denameList = new ArrayList<>();
  
  private final Map<L1ItemInstance, Integer> _sellList;
  
  private final Map<Integer, int[]> _buyList;
  
  private String _shop_chat1;
  
  private String _shop_chat2;
  
  private boolean _is_shop;
  
  private int _clanid;
  
  private String _clan_name;
  
  private L1EmblemIcon _emblem;
  
  private DeName _de_name;
  
  private int _classId;
  
  private static final int[][] _class_list = new int[][] { { 0, 61, 138, 734, 2786, 6658, 6671 }, { 1, 48, 37, 1186, 2796, 6661, 6650 } };
  
  private static final int maxThinkingCycle = 40;
  
  private int thinkingCounter;
  
  private String _global_chat;
  
  private int _chat_mode;
  
  private boolean _chat;
  
  private boolean _is_fishing;
  
  private int _fishX;
  
  private int _fishY;
  
  private L1Character attacker_target;
  
  public L1DeInstance(L1Npc template) {
    super(template);
    this._sellList = new HashMap<>();
    this._buyList = (Map)new HashMap<>();
    this._shop_chat1 = null;
    this._shop_chat2 = null;
    this._is_shop = false;
    this._clanid = 0;
    this._clan_name = null;
    this._emblem = null;
    this._de_name = null;
    this._global_chat = null;
    this._chat_mode = 0;
    this._chat = false;
    this._is_fishing = false;
    this._fishX = -1;
    this._fishY = -1;
    startNpc();
  }
  
  public L1DeInstance(L1Npc template, DeName de) {
    super(template);
    this._sellList = new HashMap<>();
    this._buyList = (Map)new HashMap<>();
    this._shop_chat1 = null;
    this._shop_chat2 = null;
    this._is_shop = false;
    this._clanid = 0;
    this._clan_name = null;
    this._emblem = null;
    this._de_name = null;
    this._global_chat = null;
    this._chat_mode = 0;
    this._chat = false;
    this._is_fishing = false;
    this._fishX = -1;
    this._fishY = -1;
    this._de_name = de;
    startNpc();
  }
  
  public void onPerceive(L1PcInstance perceivedFrom) {
    try {
      if (!this._is_shop)
        start_shop(); 
      perceivedFrom.addKnownObject((L1Object)this);
      perceivedFrom.sendPackets((ServerBasePacket)new S_NPCPack_De(this));
      if (isShop()) {
        perceivedFrom.sendPackets((ServerBasePacket)new S_DoActionShop(getId(), this._shop_chat1));
        return;
      } 
      if (isFishing()) {
        perceivedFrom.sendPackets((ServerBasePacket)new S_Fishing(getId(), 71, this._fishX, this._fishY));
        return;
      } 
      onNpcAI();
      if (getBraveSpeed() == 1)
        perceivedFrom.sendPackets((ServerBasePacket)new S_SkillBrave(getId(), 1, 600000)); 
    } catch (Exception e) {
      _log.error(e.getLocalizedMessage(), e);
    } 
  }
  
  private void startNpc() {
    try {
      if (this._de_name == null) {
        DeName[] des = DeNameTable.get().getDeNameList();
        int length = des.length;
        DeName de = des[_random.nextInt(length)];
        while (_denameList.contains(de))
          de = des[_random.nextInt(length)]; 
        this._de_name = de;
      } 
      _denameList.add(this._de_name);
      setNameId(this._de_name.get_name());
      int classid = _class_list[this._de_name.get_sex()][this._de_name.get_type()];
      int starus = 0;
      switch (classid) {
        case 0:
        case 1:
          starus = 4;
          break;
        case 48:
        case 61:
          starus = 50;
          break;
        case 37:
        case 138:
          starus = 20;
          setBowActId(66);
          set_ranged(10);
          break;
        case 734:
        case 1186:
          starus = 40;
          break;
        case 2786:
        case 2796:
          starus = 54;
          break;
        case 6658:
        case 6661:
          starus = 24;
          break;
        case 6650:
        case 6671:
          starus = 58;
          break;
      } 
      if (this._de_name.get_clanid() != 0)
        ClanReading.get().getTemplate(this._de_name.get_clanid()); 
      setStatus(starus);
      setClassId(classid);
      setTempCharGfx(classid);
      setGfxId(classid);
      setTitle(DeTitleTable.get().getTitle());
      setBraveSpeed(1);
      setMoveSpeed(1);
      int attack = SprTable.get().getAttackSpeed(classid, 1);
      int move = SprTable.get().getMoveSpeed(classid, getStatus());
      setPassispeed(move);
      setAtkspeed(attack);
    } catch (Exception e) {
      _log.error(e.getLocalizedMessage(), e);
    } 
  }
  
  public int getClassId() {
    return this._classId;
  }
  
  public void setClassId(int i) {
    this._classId = i;
  }
  
  public DeName get_deName() {
    return this._de_name;
  }
  
  public int get_chat_mode() {
    return this._chat_mode;
  }
  
  public String get_chat() {
    return this._global_chat;
  }
  
  public void set_chat(String chat, int cmd) {
    this._global_chat = chat;
    this._chat_mode = cmd;
    if (_random.nextInt(100) <= 30)
      this._chat = true; 
  }
  
  public void globalChat() {
    try {
      S_ChatTransaction s_ChatTransaction = null;
      if (_random.nextBoolean())
        return; 
      ServerBasePacket pack = null;
      if (this._chat_mode != 27) {
        S_ChatGlobal s_ChatGlobal = new S_ChatGlobal(this, this._global_chat);
      } else if (this._chat_mode != 28) {
        s_ChatTransaction = new S_ChatTransaction(this, this._global_chat);
      } 
      Iterator<L1PcInstance> iter = World.get().getAllPlayers().iterator();
      while (iter.hasNext()) {
        L1PcInstance listner = iter.next();
        if (listner.getExcludingList().contains(getNameId()))
          continue; 
        if (!listner.isShowTradeChat())
          continue; 
        listner.sendPackets((ServerBasePacket)s_ChatTransaction);
      } 
      if (this._chat)
        return; 
      S_Chat s_Chat = new S_Chat(this, this._global_chat);
      Iterator<L1PcInstance> iterator = World.get().getRecognizePlayer((L1Object)this).iterator();
      while (iterator.hasNext()) {
        L1PcInstance listner2 = iterator.next();
        if (!listner2.getExcludingList().contains(getNameId()) && 
          get_showId() == listner2.get_showId())
          listner2.sendPackets((ServerBasePacket)s_Chat); 
      } 
    } catch (Exception e) {
      _log.error(e.getLocalizedMessage(), e);
    } 
  }
  
  public boolean isFishing() {
    return this._is_fishing;
  }
  
  public void start_fishingAI() {
    if (!this._is_fishing) {
      Fishing_Runnable runnable = new Fishing_Runnable(this);
      runnable.startCmd();
    } 
  }
  
  public void stop_fishing() {
    if (this._is_fishing)
      broadcastPacketAll((ServerBasePacket)new S_CharVisualUpdate(getId(), 0)); 
    this._is_fishing = false;
  }
  
  public void start_fishing() {
    try {
      int locx = getX();
      int locy = getY();
      int count = 3 + _random.nextInt(2);
      int i = 0;
      while (i < count) {
        locx += L1Character.HEADING_TABLE_X[getHeading()];
        locy += L1Character.HEADING_TABLE_Y[getHeading()];
        i++;
      } 
      int gab = getMap().getOriginalTile(locx, locy);
      if (gab % 28 == 0) {
        this._fishX = locx;
        this._fishY = locy;
        setHeading(targetDirection(this._fishX, this._fishY));
        broadcastPacketAll((ServerBasePacket)new S_ChangeHeading(this));
        broadcastPacketAll((ServerBasePacket)new S_Fishing(getId(), 71, this._fishX, this._fishY));
        this._is_fishing = true;
      } 
    } catch (Exception e) {
      _log.error(e.getLocalizedMessage(), e);
    } 
  }
  
  public int get_fishX() {
    return this._fishX;
  }
  
  public int get_fishY() {
    return this._fishY;
  }
  
  public void setNpcSpeed() {
    try {
      if (!getDolls().isEmpty()) {
        Object[] array;
        int length = (array = getDolls().values().toArray()).length;
        int i = 0;
        while (i < length) {
          Object obj = array[i];
          L1DollInstance doll = (L1DollInstance)obj;
          if (doll != null)
            doll.setNpcMoveSpeed(); 
          i++;
        } 
      } 
    } catch (Exception e) {
      _log.error(e.getLocalizedMessage(), e);
    } 
  }
  
  public void searchTarget() {
    try {
      int classid;
      if (isShop())
        return; 
      if (isSafetyZone())
        return; 
      if (getBowActId() > 0) {
        classid = 8913;
      } else {
        classid = 6137;
      } 
      if (getTempCharGfx() != classid && _random.nextInt(100) < 70) {
        setClassId(classid);
        setTempCharGfx(classid);
        setGfxId(classid);
        int attack = SprTable.get().getAttackSpeed(classid, 1);
        int move = SprTable.get().getMoveSpeed(classid, getStatus());
        setPassispeed(move);
        setAtkspeed(attack);
        try {
          Thread.sleep(500L);
        } catch (Exception exception) {}
        broadcastPacketAll((ServerBasePacket)new S_ChangeShape(this, classid));
        try {
          Thread.sleep(2000L);
        } catch (Exception exception) {}
        searchTarget();
        return;
      } 
      L1NpcInstance targetNpc = search_target();
      if (targetNpc != null) {
        this._hateList.add(targetNpc, 0);
        this._target = targetNpc;
        if (!getPetList().isEmpty()) {
          Iterator<L1NpcInstance> iter = getPetList().values().iterator();
          while (iter.hasNext()) {
            L1NpcInstance summon = iter.next();
            if (summon != null && summon instanceof L1SummonInstance) {
              L1SummonInstance su = (L1SummonInstance)summon;
              su.setMasterTarget(this._target);
            } 
          } 
        } 
      } 
    } catch (Exception e) {
      _log.error(e.getLocalizedMessage(), e);
    } 
  }
  
  private L1NpcInstance search_target() {
    if (isDead())
      return null; 
    if (isParalyzed() || isSleeped() || hasSkillEffect(50) || hasSkillEffect(87) || 
      hasSkillEffect(157))
      return null; 
    if (this.thinkingCounter >= 40) {
      this.thinkingCounter = 10;
      L1Location newLoc = getLocation().randomLocation(200, true);
      teleport(newLoc.getX(), newLoc.getY(), 5);
      return null;
    } 
    L1NpcInstance attacker_target = null;
    if (this._target == null) {
      L1NpcInstance next_target = null;
      int minDistance = 32767;
      int distance = 0;
      ArrayList<L1Object> screenObjects = World.get().getVisibleObjects((L1Object)this, this.thinkingCounter);
      Iterator<L1Object> iterator = screenObjects.iterator();
      while (iterator.hasNext()) {
        L1Object visible = iterator.next();
        if (visible instanceof L1MonsterInstance) {
          L1MonsterInstance npc = (L1MonsterInstance)visible;
          if (npc.getCurrentHp() <= 0 || npc.isDead() || (npc.isParalyzed() && !npc.hasSkillEffect(87)) || 
            npc.getHiddenStatus() != 0 || npc.getMaxHp() < 80 || npc.getLevel() <= 5 || 
            npc.getCurrentHp() < npc.getMaxHp())
            continue; 
          if (!glanceCheck(npc.getX(), npc.getY()))
            continue; 
          if (npc._target != this)
            continue; 
          distance = getLocation().getTileLineDistance((Point)npc.getLocation());
          if (minDistance <= distance)
            continue; 
          minDistance = distance;
          next_target = npc;
        } 
      } 
      if (next_target == null) {
        Iterator<L1Object> iterator2 = screenObjects.iterator();
        while (iterator2.hasNext()) {
          L1Object visible = iterator2.next();
          if (visible instanceof L1MonsterInstance) {
            L1MonsterInstance npc = (L1MonsterInstance)visible;
            if (npc.getCurrentHp() <= 0 || npc.isDead() || (npc.isParalyzed() && !npc.hasSkillEffect(87)) || 
              npc.getHiddenStatus() != 0 || npc.getMaxHp() < 80 || npc.getLevel() <= 5 || 
              npc.getCurrentHp() < npc.getMaxHp())
              continue; 
            if (!glanceCheck(npc.getX(), npc.getY()))
              continue; 
            if (!npc.getHateList().isEmpty() && !npc.getHateList().containsKey(this))
              continue; 
            distance = getLocation().getTileLineDistance((Point)npc.getLocation());
            if (minDistance <= distance)
              continue; 
            minDistance = distance;
            next_target = npc;
          } 
        } 
      } 
      if (next_target != null)
        attacker_target = next_target; 
    } 
    if (attacker_target == null) {
      this.thinkingCounter += 5;
      return null;
    } 
    return attacker_target;
  }
  
  public boolean noTarget() {
    return !(!isShop() && !isSafetyZone());
  }
  
  public void onNpcAI() {
    try {
      if (isShop())
        return; 
      if (isAiRunning())
        return; 
      setActived(false);
      startAI();
    } catch (Exception e) {
      _log.error(e.getLocalizedMessage(), e);
    } 
  }
  
  public void onTalkAction(L1PcInstance pc) {}
  
  public void onAction(L1PcInstance pc) {
    try {
      if (isSafetyZone() || pc.isSafetyZone()) {
        L1AttackPc l1AttackPc = new L1AttackPc(pc, this);
        l1AttackPc.action();
        return;
      } 
      if (getCurrentHp() > 0 && !isDead()) {
        L1AttackPc l1AttackPc = new L1AttackPc(pc, this);
        if (l1AttackPc.calcHit())
          l1AttackPc.calcDamage(); 
        l1AttackPc.action();
        l1AttackPc.commit();
      } 
    } catch (Exception e) {
      _log.error(e.getLocalizedMessage(), e);
    } 
  }
  
  public void ReceiveManaDamage(L1Character attacker, int mpDamage) {
    if (mpDamage > 0 && !isDead()) {
      setHate(attacker, mpDamage);
      onNpcAI();
      if (attacker instanceof L1PcInstance)
        serchLink((L1PcInstance)attacker, getNpcTemplate().get_family()); 
      int newMp = getCurrentMp() - mpDamage;
      if (newMp < 0)
        newMp = 0; 
      setCurrentMp(newMp);
    } 
  }
  
  public void receiveDamage(L1Character attacker, int damage) {
    if (getCurrentHp() > 0 && !isDead()) {
      if (getHiddenStatus() == 1 || getHiddenStatus() == 2)
        return; 
      onNpcAI();
      if (attacker instanceof L1PcInstance) {
        if (damage > 0) {
          L1PcInstance player = (L1PcInstance)attacker;
          player.setPetTarget(this);
          this.thinkingCounter += 15;
          return;
        } 
      } else {
        damage += 20;
      } 
      if (damage >= 0 && !(attacker instanceof L1EffectInstance))
        if (attacker instanceof L1IllusoryInstance) {
          L1IllusoryInstance ill = (L1IllusoryInstance)attacker;
          attacker = ill.getMaster();
          setHate(attacker, damage);
        } else {
          setHate(attacker, damage);
        }  
      if (damage > 0)
        removeSkillEffect(66); 
      if (_random.nextInt(100) < 90) {
        int i = getCurrentHp() + 90;
        int[] x = { 197 };
        setCurrentHp(i);
        broadcastPacketX8((ServerBasePacket)new S_SkillSound(getId(), x[_random.nextInt(x.length)]));
      } 
      int newHp = getCurrentHp() - damage;
      if (newHp <= 0 && !isDead()) {
        setCurrentHpDirect(0);
        setDead(true);
        setStatus(8);
        Death death = new Death(attacker);
        DeAiThreadPool.get().execute(death);
      } 
      if (newHp > 0)
        setCurrentHp(newHp); 
    } else if (!isDead()) {
      setDead(true);
      setStatus(8);
      Death death2 = new Death(attacker);
      DeAiThreadPool.get().execute(death2);
    } 
  }
  
  public void setCurrentHp(int i) {
    int currentHp = Math.min(i, getMaxHp());
    if (getCurrentHp() == currentHp)
      return; 
    setCurrentHpDirect(currentHp);
  }
  
  public void setCurrentMp(int i) {
    int currentMp = Math.min(i, getMaxMp());
    if (getCurrentMp() == currentMp)
      return; 
    setCurrentMpDirect(currentMp);
  }
  
  public int getClanid() {
    return this._clanid;
  }
  
  public String getClanname() {
    return this._clan_name;
  }
  
  public L1EmblemIcon getEmblem() {
    return this._emblem;
  }
  
  public void setShopChat(String shopChat1, String shopChat2) {
    this._shop_chat1 = shopChat1;
    this._shop_chat2 = shopChat2;
  }
  
  public void shopChat() {
    try {
      if (_random.nextBoolean()) {
        String info = "";
        if (_random.nextBoolean()) {
          info = this._shop_chat1;
        } else {
          info = this._shop_chat2;
        } 
        broadcastPacketAll((ServerBasePacket)new S_DoActionShop(getId(), info));
      } 
    } catch (Exception e) {
      _log.error(e.getLocalizedMessage(), e);
    } 
  }
  
  public void stop_shop() {
    try {
      if (isShop()) {
        set_isShop(false);
        this._sellList.clear();
        this._buyList.clear();
        this._shop_chat1 = null;
        this._shop_chat2 = null;
        broadcastPacketAll((ServerBasePacket)new S_CharVisualUpdate(getId(), 0));
      } 
    } catch (Exception e) {
      _log.error(e.getLocalizedMessage(), e);
    } 
  }
  
  public void start_shop() {
    try {
      if (!isShop()) {
        boolean isShopMap = false;
        boolean isShopMap2 = false;
        switch (getMapId()) {
          case 340:
            isShopMap2 = true;
            break;
          case 350:
          case 360:
          case 370:
          case 800:
            isShopMap = true;
            break;
        } 
        if (isShopMap) {
          set_isShop(true);
          DeShopItemTable.get().getItems(this);
          int h = _random.nextInt(7);
          setHeading(h);
          broadcastPacketX8((ServerBasePacket)new S_ChangeHeading(this));
          broadcastPacketX8((ServerBasePacket)new S_DoActionShop(getId(), this._shop_chat1));
          int[] PolyList = { 10032, 11427, 10047, 9688, 11322, 10069, 10034, 10032 };
          int polyIndex = _random.nextInt(8);
          setStatus(0);
          setTempCharGfx(PolyList[polyIndex]);
          broadcastPacketX8((ServerBasePacket)new S_CharVisualUpdate(getId(), 70));
        } 
      } 
    } catch (Exception e) {
      _log.error(e.getLocalizedMessage(), e);
    } 
  }
  
  public Map<L1ItemInstance, Integer> get_sellList() {
    return this._sellList;
  }
  
  public Map<Integer, int[]> get_buyList() {
    return this._buyList;
  }
  
  public void sellList(Map<L1ItemInstance, Integer> sellList) {
    this._sellList.putAll(sellList);
  }
  
  public void buyList(Map<Integer, int[]> buyList) {
    this._buyList.putAll((Map)buyList);
  }
  
  public void updateBuyList(Integer key, int[] value) {
    this._buyList.put(key, value);
  }
  
  private class Fishing_Runnable implements Runnable {
    private L1DeInstance _npc;
    
    private Fishing_Runnable(L1DeInstance npc) {
      this._npc = null;
      this._npc = npc;
    }
    
    private void startCmd() {
      DeAiThreadPool.get().execute(this);
    }
    
    public void run() {
      try {
        int x = this._npc.getX();
        int y = this._npc.getY();
        int x2 = x - 18;
        int y2 = y - 18;
        int x3 = x + 18;
        int y3 = y + 18;
        int rows = x3 - x2;
        int columns = y3 - y2;
        int tgx = 0;
        int tgy = 0;
        L1Map map = this._npc.getMap();
        int i = 0;
        while (i < rows) {
          int j = 0;
          while (j < columns) {
            int cx = x2 + i;
            int cy = y2 + j;
            int gab = map.getOriginalTile(cx, cy);
            if (gab % 28 == 0) {
              tgx = cx;
              tgy = cy;
            } 
            j++;
          } 
          i++;
        } 
        Thread.sleep(10L);
        i = 20;
        while (this._npc.getX() != tgx && this._npc.getY() != tgy && 
          this._npc != null) {
          double d = this._npc.getLocation().getLineDistance(new Point(tgx, tgy));
          if (d <= 1.0D)
            break; 
          int moveDirection = this._npc.getMove().moveDirection(tgx, tgy);
          int dir = this._npc.getMove().checkObject(moveDirection);
          if (dir != -1) {
            this._npc.getMove().setDirectionMove(dir);
            this._npc.setNpcSpeed();
          } 
          Thread.sleep(this._npc.calcSleepTime(this._npc.getPassispeed(), 0));
          if (--i <= 0)
            break; 
        } 
        Thread.sleep(5000L);
        L1DeInstance.this.start_fishing();
      } catch (InterruptedException e) {
        L1DeInstance._log.error(e.getLocalizedMessage(), e);
      } 
    }
  }
  
  class Death implements Runnable {
    L1Character _lastAttacker;
    
    public Death(L1Character lastAttacker) {
      this._lastAttacker = lastAttacker;
    }
    
    public void run() {
      try {
        L1DeInstance mob = L1DeInstance.this;
        L1DeInstance._denameList.remove(L1DeInstance.this._de_name);
        mob.setDeathProcessing(true);
        mob.setCurrentHpDirect(0);
        mob.setDead(true);
        mob.setStatus(8);
        mob.broadcastPacketAll((ServerBasePacket)new S_DoActionGFX(mob.getId(), 8));
        mob.getMap().setPassable((Point)mob.getLocation(), true);
        mob.startChat(1);
        mob.setDeathProcessing(false);
        mob.allTargetClear();
        int deltime = 5;
        mob.startDeleteTimer(5);
        ListMapUtil.clear(L1DeInstance.this._sellList);
        ListMapUtil.clear(L1DeInstance.this._buyList);
      } catch (Exception e) {
        L1DeInstance._log.error(e.getLocalizedMessage(), e);
      } 
    }
  }
}
